package com.miniprogram.api.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.miniprogram.api.config.WxMaConfiguration;
import com.miniprogram.api.config.WxMaProperties;
import com.miniprogram.api.service.ICustomerUserService;
import com.miniprogram.api.utils.ShiroUtils;
import com.miniprogram.bean.po.CustomerUser;
import com.miniprogram.bean.po.CustomerUserToken;
import com.miniprogram.bean.qo.api.LoginByAccountQo;
import com.miniprogram.common.dto.ResponseVo;
import com.miniprogram.common.enums.CustomerUserStatusEnum;
import com.miniprogram.common.enums.RestStatusEnum;
import com.miniprogram.common.utils.Shift;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Date;

@Api("登陆Controller")
@RestController
@Slf4j
@RequestMapping("/login")
public class LoginController extends AbstractController {

    @Autowired
    private ICustomerUserService iCustomerUserService;

    @Autowired
    private WxMaProperties wxMaProperties;

    @Value("${spring.profiles.active}")
    private String profiles;

    @ApiOperation(value = "用户注册接口", notes = "用户注册接口", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "openId", value = "微信号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "headImg", value = "头像", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "nickName", value = "用户昵称", required = true, dataType = "String", paramType = "query")
    })
    @PostMapping("/register")
    @ResponseBody
    public ResponseVo<String> register(String openId, String headImg, String nickName) {
        if (StringUtils.isEmpty(openId)) {
            Shift.fatal(RestStatusEnum.PHONE_NOTNULL);
        }
        CustomerUser user = new CustomerUser();
        String now = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN);
        user.setAccount(now);
        user.setUsername("用户" + System.currentTimeMillis());
        user.setHeadImg(headImg);
        user.setNickName(nickName);
        user.setOpenId(openId);
        user.setPassword("123456");
        user.setStatus(CustomerUserStatusEnum.NORMAL.getCode());
        boolean flag = this.iCustomerUserService.save(user);
        if (!flag) {
            Shift.fatal(RestStatusEnum.REGISTER_WRONG);
        }
        return new ResponseVo<>("注册成功");
    }


    @ApiOperation(value = "根据密码登录", notes = "根据密码登录", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "微信code", required = true, dataType = "String", paramType = "query")
    })
    @PostMapping("/loginByCode")
    @ResponseBody
    public ResponseVo<CustomerUser> loginByCode(String code) {
        if (StringUtils.isEmpty(code)) {
            return new ResponseVo<>(RestStatusEnum.PARAMETER_NOTNULL);
        }
        String openId = "";
        try {
            if ("dev".equals(profiles)) {
                openId = "123456";
            } else if ("prod".equals(profiles)) {
                final WxMaService wxService = WxMaConfiguration.getMaService(wxMaProperties.getConfigs().get(0).getAppid());
                WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
                openId = session.getOpenid();
            }
        } catch (Exception e) {
            log.error("小程序登录失败，失败原因为", e);
            return new ResponseVo<>(RestStatusEnum.ERROR);
        }
        CustomerUser user = this.iCustomerUserService.getByOpenId(openId);
        if (user == null) {
            // 用户不存在，要重新走注册登录
            Shift.fatal(RestStatusEnum.USER_NOTFOUND, openId);
        }
        String account = user.getAccount();
        String password = user.getPassword();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getAccount(), user.getPassword(), true);
        // 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            log.info("account为：，密码为：{}的用户认证成功", account, password);
        } catch (UnknownAccountException e) {
            log.error("account为：{}，密码为：{}的用户account不存在", account, password);
            return new ResponseVo<>(RestStatusEnum.LOGIN_ERROR, e.getMessage());
        } catch (IncorrectCredentialsException e) {
            log.error("account为：{}，密码为：{}的用户密码错误", account, password);
            return new ResponseVo<>(RestStatusEnum.LOGIN_ERROR, e.getMessage());
        } catch (LockedAccountException e) {
            log.error("account为：{}，密码为：{}的用户已被锁定", account, password);
            return new ResponseVo<>(RestStatusEnum.LOGIN_ERROR, e.getMessage());
        } catch (AuthenticationException e) {
            log.error("account为：{}，密码为：{}的用户认证失败", account, password);
            return new ResponseVo<>(RestStatusEnum.LOGIN_ERROR, e.getMessage());
        }
        return new ResponseVo<>(user);
    }

    /**
     * 登陆成功的返回值接口
     */
    @ApiOperation(value = "登陆成功返回接口", notes = "当登陆成功后，返回该信息", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @GetMapping("/loginSuccess")
    @ResponseBody
    public ResponseVo<String> loginSuccess() {
        return new ResponseVo<>(RestStatusEnum.LOGIN_SUCCESS);
    }

    /**
     * 登陆失败的返回值接口
     */
    @ApiOperation(value = "登录失败返回接口", notes = "当登陆失败后，返回该信息", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @GetMapping("/loginError")
    @ResponseBody
    public ResponseVo<String> loginError() {
        return new ResponseVo<>(RestStatusEnum.LOGIN_ERROR);
    }

    @ApiOperation(value = "登出", notes = "登出", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @GetMapping("/loginOut")
    @ResponseBody
    public ResponseVo<String> loginOut() {
        ShiroUtils.logout();
        return new ResponseVo<>(RestStatusEnum.SUCCESS);
    }

    @ApiOperation(value = "获取小程序二维码", notes = "获取小程序二维码", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @GetMapping("/getQrcode")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "scene", value = "最大32个可见字符", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "已发布的小程序页面", required = true, dataType = "String", paramType = "query"),
    })
    @ResponseBody
    public ResponseVo<byte[]> getQrcode(String scene, String page) throws Exception {
        byte[] bytes = WxMaConfiguration.getMaService(wxMaProperties.getConfigs().get(0).getAppid()).getQrcodeService().createWxaCodeUnlimitBytes(scene, page, 430, true, null, false);
        return new ResponseVo<>(bytes);
    }

    @ApiOperation(value = "系统：使用账号密码登录", notes = "使用账号密码登录", produces = "application/json, application/xml", consumes = "application/json, application/xml")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "account", value = "账号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "query")
    })
    @PostMapping("/loginByAccount")
    @ResponseBody
    public ResponseVo<CustomerUserToken> loginByAccount(@RequestBody LoginByAccountQo qo) {
        if (!StringUtils.hasText(qo.getAccount())) {
            Shift.fatal(RestStatusEnum.OTHER, "账号不能为空");
        }
        if (!StringUtils.hasText(qo.getPassword())) {
            Shift.fatal(RestStatusEnum.OTHER, "密码不能为空");
        }
        CustomerUserToken token = this.iCustomerUserService.login(qo.getAccount(), qo.getPassword());
        return new ResponseVo<>(token);
    }

}
